package com.yiyi.filter;

import com.alibaba.fastjson.JSONObject;
import com.yiyi.config.JwtConfigProperties;
import com.yiyi.util.ResponseUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * User: YIYI
 * Date: 2021-08-10
 * Time: 16:29
 * Description: token校验类
 */

@Slf4j
public class JWTAuthenticationFilter extends BasicAuthenticationFilter {

    private Integer tokenExpireTime;

    @Autowired
    private JwtConfigProperties jwtConfigProperties;

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager, Integer tokenExpireTime) {
        super(authenticationManager);
        this.tokenExpireTime = tokenExpireTime;
    }

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager, AuthenticationEntryPoint authenticationEntryPoint) {
        super(authenticationManager, authenticationEntryPoint);
    }

    /**
     * 通过前端口提供的请求，解析header是否有token，解析后处理SecurityContextHolder
     *
     * @param request
     * @param response
     * @param chain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {

        String header = request.getHeader("Authorization");

        Boolean notValid = StringUtils.isBlank(header);
        if (notValid) {
            chain.doFilter(request, response);
            return;
        }

        if (jwtConfigProperties == null) {
            BeanFactory factory = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());
            jwtConfigProperties = (JwtConfigProperties) factory.getBean("jwtConfigProperties");
        }

        try {
            //UsernamePasswordAuthenticationToken 继承 AbstractAuthenticationToken 实现 Authentication
            //所以当在页面中输入用户名和密码之后首先会进入到 UsernamePasswordAuthenticationToken验证(Authentication)，
            UsernamePasswordAuthenticationToken authentication = getAuthentication(header, response);
            SecurityContextHolder.getContext().setAuthentication(authentication);
        } catch (Exception e) {
            e.toString();
        }
        chain.doFilter(request, response);
    }

    /**
     * 解析token后返回UsernamePasswordAuthenticationToken
     *
     * @param header
     * @param response
     * @return
     */
    private UsernamePasswordAuthenticationToken getAuthentication(String header, HttpServletResponse response) {

        //用户名
        String username = null;

        //定义权限列表
        List<GrantedAuthority> authorities = new ArrayList<>();

        try {
            //解析token
            Claims claims = Jwts.parser()
                    .setSigningKey(jwtConfigProperties.getSecret())
                    .parseClaimsJws(header)
                    .getBody();
            logger.info("claims：" + claims);

            //获取用户名
            username = claims.getSubject();
            logger.info("username：" + username);

            //获取权限
            String authorityStr = claims.get("authorities").toString();
            logger.info("authority：" + authorityStr);

            List<String> list = JSONObject.parseArray(authorityStr, String.class);
            authorities = list.stream().map(a -> new SimpleGrantedAuthority(a)).collect(Collectors.toList());

            //if (!StringUtils.isEmpty(authority)) {
            //    authorities.add(new SimpleGrantedAuthority(authority));
            //}

            //authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));

        } catch (ExpiredJwtException e) {
            ResponseUtil.out(response, ResponseUtil.resultMap(false, 401, "登录已失效，请重新登录"));
        } catch (Exception e) {
            log.error(e.toString());
            ResponseUtil.out(response, ResponseUtil.resultMap(false, 500, "解析token错误"));
        }

        if (StringUtils.isNotBlank(username)) {
            //踩坑提醒 此处password不能为null
            User principal = new User(username, "", authorities);
            return new UsernamePasswordAuthenticationToken(principal, null, authorities);
        }
        return null;
    }
}